/*
 * @FileName: bsp_adc.c
 * @Author: GreyQiu qiushaogui@aikosolar.com
 * @Date: 2023-07-12 16:05:59
 * @LastEditors: GreyQiu qiushaogui@aikosolar.com
 * @LastEditTime: 2023-09-23 13:40:56
 * @Description: 
 * 
 * Copyright (c) 2023, All Rights Reserved. 
 */

#include "bsp.h"
#include "bsp_adc.h"
#include "spll_1ph_notch.h"
#include "spll_1ph_sogi.h"
#include "loop.h"
#include "app_analog.h"
//SPLL_1PH_NOTCH spll2;
SPLL_1PH_SOGI spll2;

uint16_t g_vin_raw = 0;
uint16_t g_iin_raw = 0;
uint16_t g_vout_raw = 0;

// 每一路输入，每个PWM周期触发2次，每次采样3个量，即每个量1个周期采样2次
// 采样完成后通过DMA搬运到以下数组，数组中保存采样4次的量用来求平均值
// 数组每个元素含义：vin0, iin0, vout0, vin1, iin1, vout1,.... vin3, iin3, vout3
uint16_t adc_buf_pv1[6];
uint16_t adc_buf_pv2[6];
uint16_t adc_buf_bat1[6];
uint16_t adc_buf_bat2[6];

uint16_t fsbbMode = 0;

//*****************************************************************************
//
// ASYSCTL Configurations
//
//*****************************************************************************
void ASYSCTL_init(){
    //
    // asysctl initialization
    //
    // Disables the temperature sensor output to the ADC.
    //
    ASysCtl_disableTemperatureSensor();
    //
    // Set the analog voltage reference selection to internal.
    //
    ASysCtl_setAnalogReferenceInternal( ASYSCTL_VREFHIA | ASYSCTL_VREFHIC );
    //
    // Set the internal analog voltage reference selection to 1.65V.
    //
    ASysCtl_setAnalogReference1P65( ASYSCTL_VREFHIA | ASYSCTL_VREFHIC );
}

/**
 * @description: 配置ADC
 */
static void adc_gpio_config(void) {
    // PV1输入电压 A6 GPIO228
    GPIO_setPinConfig(GPIO_228_GPIO228);
    GPIO_setAnalogMode(228, GPIO_ANALOG_ENABLED);

    // PV1输出电压 A11 GPIO237
    GPIO_setPinConfig(GPIO_237_GPIO237);
    GPIO_setAnalogMode(237, GPIO_ANALOG_ENABLED);

    // PV1输入电流 A2 GPIO224
    GPIO_setPinConfig(GPIO_224_GPIO224);
    GPIO_setAnalogMode(224, GPIO_ANALOG_ENABLED);

    // PV1电感电流 A0 GPIO231
    GPIO_setPinConfig(GPIO_231_GPIO231);
    GPIO_setAnalogMode(231, GPIO_ANALOG_ENABLED);

    // PV2电感电流 A12 GPIO238
    GPIO_setPinConfig(GPIO_238_GPIO238);
    GPIO_setAnalogMode(238, GPIO_ANALOG_ENABLED);
}

/**
 * @description: 配置ADCA, 用于PV控制
 */
static void adca_config(void) {
    // ADC基准选择内部3.3V
    ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);

    // ADC时钟
    ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_3_0);

    // ADC中断触发点，
    ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_ACQ_WIN); // 信号采集完即触发中断
    ADC_setInterruptCycleOffset(ADCA_BASE, 0); // 以采集完成为基准点，中断触发点往后偏移

    ADC_enableConverter(ADCA_BASE); // ADC上电

    DEVICE_DELAY_US(5000); // 等待ADC上电完成

    ADC_disableBurstMode(ADCA_BASE); // 禁止突发模式

    ADC_setSOCPriority(ADCA_BASE, ADC_PRI_ALL_ROUND_ROBIN); // ADC轮询触发

    // PV1 第一次采样 PWM三角调制波谷底触发
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN6, 8U);    // VIN
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN2, 8U);    // IIN
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM1_SOCA, ADC_CH_ADCIN11, 8U);   // VOUT
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER2, ADC_INT_SOC_TRIGGER_NONE);

    // PV1 第二次采样 PWM三角调制波峰顶触发
    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER4, ADC_TRIGGER_EPWM1_SOCB, ADC_CH_ADCIN6, 8U);    // VIN
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER3, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM1_SOCB, ADC_CH_ADCIN2, 8U);    // IIN
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER4, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER5, ADC_TRIGGER_EPWM1_SOCB, ADC_CH_ADCIN11, 8U);   // VOUT
    ADC_setInterruptSOCTrigger(ADCA_BASE, ADC_SOC_NUMBER5, ADC_INT_SOC_TRIGGER_NONE);

    // A2通道采集完成时触发中断ADCA1
    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER5);
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_disableContinuousMode(ADCA_BASE, ADC_INT_NUMBER1);
    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);

//    // A5通道采集完成时触发中断ADCA2
//    ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER2, ADC_SOC_NUMBER5);
//    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER2);
//    ADC_disableContinuousMode(ADCA_BASE, ADC_INT_NUMBER2);
//    ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER2);
}

/**
 * @description: 配置ADCC, 用于BAT控制
 */
static void adcc_config(void) {
    // ADC基准选择内部3.3V
    ADC_setVREF(ADCC_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);

    // ADC时钟
    ADC_setPrescaler(ADCC_BASE, ADC_CLK_DIV_3_0);

    // ADC中断触发点，
    ADC_setInterruptPulseMode(ADCC_BASE, ADC_PULSE_END_OF_ACQ_WIN); // 信号采集完即触发中断
    ADC_setInterruptCycleOffset(ADCC_BASE, 0); // 以采集完成为基准点，中断触发点往后偏移

    ADC_enableConverter(ADCC_BASE); // ADC上电

    DEVICE_DELAY_US(5000); // 等待ADC上电完成

    ADC_disableBurstMode(ADCC_BASE); // 禁止突发模式

    ADC_setSOCPriority(ADCC_BASE, ADC_PRI_ALL_ROUND_ROBIN); // ADC轮询触发

    // PV1每周期第一次采样
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_EPWM3_SOCA, ADC_CH_ADCIN6, 8U); // C0 -> PV1 Vin
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER0, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_EPWM3_SOCA, ADC_CH_ADCIN0, 8U); // C1 -> PV1 Iin
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER1, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER2, ADC_TRIGGER_EPWM3_SOCA, ADC_CH_ADCIN11, 8U); // C2 -> PV1 Vout
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER2, ADC_INT_SOC_TRIGGER_NONE);

    // PV1每周期第二次采样
    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER3, ADC_TRIGGER_EPWM4_SOCA, ADC_CH_ADCIN3, 8U); // C3 -> PV2 Vin
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER3, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER4, ADC_TRIGGER_EPWM4_SOCA, ADC_CH_ADCIN4, 8U); // C4 -> PV2 Iin
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER4, ADC_INT_SOC_TRIGGER_NONE);

    ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER5, ADC_TRIGGER_EPWM4_SOCA, ADC_CH_ADCIN5, 8U); // C5 -> PV2 Vout
    ADC_setInterruptSOCTrigger(ADCC_BASE, ADC_SOC_NUMBER5, ADC_INT_SOC_TRIGGER_NONE);

    // A2通道采集完成时触发中断ADCC1
    ADC_setInterruptSource(ADCC_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER2);
    ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);
    ADC_disableContinuousMode(ADCC_BASE, ADC_INT_NUMBER1);
    ADC_enableInterrupt(ADCC_BASE, ADC_INT_NUMBER1);

    // A5通道采集完成时触发中断ADCC2
    ADC_setInterruptSource(ADCC_BASE, ADC_INT_NUMBER2, ADC_SOC_NUMBER5);
    ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER2);
    ADC_disableContinuousMode(ADCC_BASE, ADC_INT_NUMBER2);
    ADC_enableInterrupt(ADCC_BASE, ADC_INT_NUMBER2);
}

//
// adcA1ISR - ADC A Interrupt 1 ISR
//
__interrupt void adcA1ISR(void)
{
    static uint16_t scaleCnt = 0;

    bsp_gpio_set(LEG_RED_PIN);
    g_vin_raw = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1) + ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER4);
    g_iin_raw = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0) + ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER3);
    g_vout_raw = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER2) + ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER5);

    analog_convert(&analog_tbl[ANALOG_ID_VIN], g_vin_raw >> 1); // 转换真实值
    analog_convert(&analog_tbl[ANALOG_ID_IIN], g_iin_raw >> 1); // 转换真实值
    analog_convert(&analog_tbl[ANALOG_ID_VOUT], g_vout_raw >> 1); // 转换真实值
    analog_filter(&analog_tbl[ANALOG_ID_VIN]);
    analog_filter(&analog_tbl[ANALOG_ID_IIN]);
    analog_filter(&analog_tbl[ANALOG_ID_VOUT]);

    if (loop_getEn() == true) {
        float dutyCnt = loop_pv1_run(analog_tbl[ANALOG_ID_VIN].real, analog_tbl[ANALOG_ID_IIN].real, analog_tbl[ANALOG_ID_VOUT].real);
        float d1, d2;

        if (dutyCnt <= 0.93f) {
            fsbbMode = 0;
        } else if (dutyCnt > 0.95f && dutyCnt <= 1.0f) {
            fsbbMode = 1;
        } else if (dutyCnt > 1.0f && dutyCnt <= 1.05f) {
            fsbbMode = 2;
        } else if (dutyCnt > 1.1f){
            fsbbMode = 3;
        }

        switch (fsbbMode) {
            case 0:
                d1 = dutyCnt;
                d2 = 0.0f;
                break;
            case 1:
                d1 = dutyCnt * 0.95f;
                d2 = 0.05f;
                break;
            case 2:
                d1 = 0.95f;
                d2 = 1 - (2.0f - dutyCnt) * 0.95f;
                break;
            case 3:
                d1 = 1.0f;
                d2 = dutyCnt - 1.0f;
                break;
            default: break;
        }

//        bsp_pwm_duty_set(EPWM1_BASE, d1 * PWM_PERIOD_CNT);
//        bsp_pwm_duty_set(EPWM2_BASE, d2 * PWM_PERIOD_CNT);
        bsp_pwm_duty_set(EPWM1_BASE, (1.0f - d2) * PWM_PERIOD_CNT);
        bsp_pwm_duty_set(EPWM2_BASE, (1.0f - d1) * PWM_PERIOD_CNT);
    }


    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);


    //
    // Check if overflow has occurred
    //
    if(true == ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1))
    {
        ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER1);
        ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
    }

    //
    // Acknowledge the interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
    bsp_gpio_reset(LEG_RED_PIN);
}

//
// adcA2ISR - ADC A Interrupt 2 ISR
//
__interrupt void adcA2ISR(void)
{
    ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER2);


    //
    // Check if overflow has occurred
    //
    if(true == ADC_getInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER2))
    {
        ADC_clearInterruptOverflowStatus(ADCA_BASE, ADC_INT_NUMBER2);
        ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER2);
    }
    //
    // Acknowledge the interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP10);
}

//
// adcC1ISR - ADC C Interrupt 1 ISR
//
__interrupt void adcC1ISR(void)
{
    ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);


    //
    // Check if overflow has occurred
    //
    if(true == ADC_getInterruptOverflowStatus(ADCC_BASE, ADC_INT_NUMBER1))
    {
        ADC_clearInterruptOverflowStatus(ADCC_BASE, ADC_INT_NUMBER1);
        ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);
    }
    //
    // Acknowledge the interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

//
// adcC2ISR - ADC C Interrupt 2 ISR
//
__interrupt void adcC2ISR(void)
{
    ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER2);


    //
    // Check if overflow has occurred
    //
    if(true == ADC_getInterruptOverflowStatus(ADCC_BASE, ADC_INT_NUMBER2))
    {
        ADC_clearInterruptOverflowStatus(ADCC_BASE, ADC_INT_NUMBER2);
        ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER2);
    }
    //
    // Acknowledge the interrupt
    //
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP10);
}



/**
 * @description: 配置ADC中断
 */
static void adc_interrupt_config(void) {
    // Interrupt Setings for INT_myADC0_1
    Interrupt_register(INT_ADCA1, &adcA1ISR);
    Interrupt_enable(INT_ADCA1);

    Interrupt_register(INT_ADCA2, &adcA2ISR);
    Interrupt_enable(INT_ADCA2);

    Interrupt_register(INT_ADCC1, &adcC1ISR);
    Interrupt_enable(INT_ADCC1);

    Interrupt_register(INT_ADCC2, &adcC2ISR);
    Interrupt_enable(INT_ADCC2);
}

//
// 配置DMA传输ADC转换结果
//
void initDMA()
{
    //
    // Refer to dma.c for the descriptions of the following functions.
    //

    //
    // Initialize DMA
    //
    DMA_initController();

    DMA_ConfigParams  transfParams;

    //
    // configure DMA CH6
    //
    transfParams.transferTrigger  = DMA_TRIGGER_ADCA1;
    transfParams.interruptMode    = DMA_INT_AT_END;
    transfParams.enableInterrupt  = 1;
    transfParams.configSize       = DMA_CFG_SIZE_16BIT;
    transfParams.transferMode     = DMA_CFG_ONESHOT_DISABLE; // 每次触发仅传输N个BUSRT
    transfParams.reinitMode       = DMA_CFG_CONTINUOUS_ENABLE; // 使能连续模式
    transfParams.burstSize        = 3; // 每次BUSRT传输3个数据，VIN,IIN,VOUT
    transfParams.transferSize     = 2; // 每次完整的DMA传输需要触发2次BURST
    transfParams.srcWrapSize      = 1; // 源地址在每1次BURST完成时重置
    transfParams.destWrapSize     = 2; // 目的地址在每2次BURST完成时重置
    transfParams.destAddr         = (uint32_t)adc_buf_pv1;
    transfParams.srcAddr          = (uint32_t)ADCARESULT_BASE; // ADCRESULT0
    transfParams.srcBurstStep     = 1; // 每传输一个数据，源地址+1
    transfParams.destBurstStep    = 1; // 每传输一个数据，目标地址+1
    transfParams.srcTransferStep  = 1; // 每完成一次busrt, 源地址+1，如果触发WRAP则重置
    transfParams.destTransferStep = 1; // 每完成一次busrt, 目的地址+1，如果触发WRAP则重置
    transfParams.srcWrapStep      = 0;
    transfParams.destWrapStep     = 0;

    DMA_configChannel(DMA_CH6_BASE, &transfParams);
}

/**
 * @description: 初始化ADC
 */
void bsp_adc_init(void) {
    adc_gpio_config();
    adca_config();
//    adcc_config();
    adc_interrupt_config();
}

